using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Resources;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
using Microsoft.BizTalk.Message.Interop;
using Microsoft.BizTalk.Component.Interop;
using Microsoft.BizTalk.Component;
using Microsoft.BizTalk.Messaging;
using System.Xml;
using System.Collections.Generic;
using System.Xml.Serialization;
using Sixeyed.CacheAdapter.Configuration;

namespace Sixeyed.CacheAdapter.PipelineComponents
{    
    /// <summary>
    /// Receive pipeline component which checks if the incoming message is configured
    /// for caching, and adds cache configuration context properties
    /// </summary>
    [ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [ComponentCategory(CategoryTypes.CATID_Any)]
    [System.Runtime.InteropServices.Guid("9CAC659E-10CE-4b0f-BFA1-7F25EAEEDAAF")]
    public class SetMessageCacheProperties : PipelineComponentBase
    {
        #region Private instance fields

        private bool _isCacheEnabled;
        private bool _isMessageTypeConfigurationEnabled;

        #endregion

        #region Design Time Properties

        /// <summary>
        /// Whether the cache is enabled
        /// </summary>
        [Browsable(true)]
        [Description("Whether the cache is enabled.")]
        public bool IsCacheEnabled 
        {
            get { return _isCacheEnabled; }
            set { _isCacheEnabled = value; }
        }

        /// <summary>
        /// Whether the cache is only enabled for configured message types
        /// </summary>
        [Browsable(true)]
        [Description("Whether the cache is only enabled for configured message types.")]
        public bool IsMessageTypeConfigurationEnabled
        {
            get { return _isMessageTypeConfigurationEnabled; }
            set { _isMessageTypeConfigurationEnabled = value; }
        }

        #endregion

        #region PipelineComponentBase overrides

        /// <summary>
        /// Gets the GUID for this component
        /// </summary>
        protected override Guid Guid
        {
            get { return new Guid("9CAC659E-10CE-4b0f-BFA1-7F25EAEEDAAF"); }
        }

        /// <summary>
        /// Populates cache configuration as contetx properties on message
        /// </summary>
        /// <param name="pc">Pipeline context</param>
        /// <param name="inmsg">Incoming message</param>
        /// <returns>Incoming message with context properties</returns>
        public override IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)
        {
            bool isMessageCacheEnabled = this.IsCacheEnabled;
            if (isMessageCacheEnabled)
            {
                TimeSpan cacheLifeSpan = TimeSpan.Zero;

                //check config to see if the message type is configured for caching:
                if (this.IsMessageTypeConfigurationEnabled)
                {
                    object value = inmsg.Context.Read(PropertyName.MessageType, Namespace.SystemProperties);
                    if (value != null && value is string)
                    {
                        string messageType = (string)value;
                        isMessageCacheEnabled = SSOConfiguration.MessageCacheConfigurationCollection.IsMessageCacheEnabled(messageType);
                        cacheLifeSpan = SSOConfiguration.MessageCacheConfigurationCollection.GetMessageCacheLifespan(messageType);
                    }
                }

                //write timespan if cache is enabled:
                if (isMessageCacheEnabled)
                {
                    inmsg.Context.Write(MessageCacheProperties.PropertyName.MessageCacheLifespan, MessageCacheProperties.Namespace.CacheAdapter, XmlConvert.ToString(cacheLifeSpan));
                }
            }
            //always write whether cache is enabled:
            inmsg.Context.Promote(MessageCacheProperties.PropertyName.IsMessageCacheEnabled, MessageCacheProperties.Namespace.CacheAdapter, isMessageCacheEnabled);
                
            return inmsg;
        }

        #endregion

        #region Overidden members

        /// <summary>
        /// Loads configuration properties for the component
        /// </summary>
        /// <param name="propertyBag">Configuration property bag</param>
        /// <param name="errlog">Error status</param>
        public override void Load(IPropertyBag propertyBag, int errlog)
        {
            object value = ReadPropertyBag(propertyBag, PropertyName.IsCacheEnabled);
            if (value != null)
            {
                this._isCacheEnabled = (bool)value;
            }
            value = ReadPropertyBag(propertyBag, PropertyName.IsMessageTypeConfigurationEnabled);
            if (value != null)
            {
                this._isMessageTypeConfigurationEnabled = (bool)value;
            }
        }

        /// <summary>
        /// Saves the current component configuration into the property bag
        /// </summary>
        /// <param name="propertyBag">Configuration property bag</param>
        /// <param name="clearDirty">not used</param>
        /// <param name="saveAllProperties">not used</param>
        public override void Save(IPropertyBag propertyBag, bool clearDirty, bool saveAllProperties)
        {
            WritePropertyBag(propertyBag, PropertyName.IsCacheEnabled, this._isCacheEnabled);
            WritePropertyBag(propertyBag, PropertyName.IsMessageTypeConfigurationEnabled, this._isMessageTypeConfigurationEnabled);
        }

        #endregion

        private struct Namespace
        {
            public const string SystemProperties = "http://schemas.microsoft.com/BizTalk/2003/system-properties";
        }

        private struct PropertyName
        {
            public const string MessageType = "MessageType";
            public const string IsCacheEnabled = "IsCacheEnabled";
            public const string IsMessageTypeConfigurationEnabled = "IsMessageTypeConfigurationEnabled";
        }

    }
}

